import Queue
import logging
import string
import StringIO
import Tkinter
import tkSimpleDialog
import ScrolledText
import os
import smtplib
import time
from MVC.plstcontroller import IController
from MVC.plstdocument import IDocument
from service.pconfig import PConfig

class FileSizeFilter (logging.Filter):
    """ File size filter. Ensure log file size under file_size_limit"""
    def __init__ (self,name,size):
        """ Setup Filter"""
        logging.Filter.__init__(self)
        self.file_name = name
        self.file_size_limit = size


    def filter (self, record):
        """Check log file size within limit """
        if os.stat(self.file_name)[6] < self.file_size_limit:
            return 1
        else:
            #Under windows os.remove a using file will raise exception
            print 'Log file overflow. Clean it up'
            # I don't wanna write platform dependenc code.
            #but it seems the only way to clean up log file
            os.popen('cat /dev/null > '+self.file_name)
            return 0


class ViewLoggerHandle(logging.Handler):
    def __init__(self,main):
        logging.Handler.__init__(self)
        self.main=main
    def emit(self,record):
        self.main.logQueue.put_nowait(record)
        self.main.Flush()

class MailLoggerHandler (logging.Handler):
    """Mail Logger
    Mail Logger send mail by using mail box infomation in pluster.cfg
    """
    def __init__(self,to_addr_list,smtp,from_addr,passwd,subject):
        """ Init Mail logger handler"""
        logging.Handler.__init__(self)
        self.to_list = to_addr_list.split(',')
        self.from_addr = from_addr
        self.passwd = passwd
        self.smtp = smtp
        self.mail_time_out = 3600  # the time between each mail
        self.last_mail_time = 0
        self.max_mail_number = 3   # max pending mail number
        self.mail_number = 0  # current pending mail number
        self.pend_mesg = ""
        self.subject = subject
        formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        self.setFormatter(formatter)

    def emit (self, record):
        """ send mail to administrators"""
        ctime = time.time()
        self.mail_number += 1
        self.pend_mesg += self.format(record)
        # If in mail_time_out or less than max_mail_number, wait.
        if ctime - self.last_mail_time < self.mail_time_out and \
                self.mail_number < self.max_mail_number:
            print """Mail pending. Pluster will send mail every %d
seconds or pending %d mails. There are %d seconds left to send next mail.
Current pending mail %d""" % (self.mail_time_out,
                              self.max_mail_number,
                              self.mail_time_out - (ctime-self.last_mail_time),
                              self.mail_number)
            return
        self.mail_number = 0
        self.last_mail_time = ctime
        try:
            server = smtplib.SMTP(self.smtp)
            #server.set_debuglevel(1)
            server.login(self.from_addr,self.passwd)
        except smtplib.SMTPException:
            server.ehlo()
            server.starttls()
            server.ehlo()
            server.login(self.from_addr,self.passwd)

        print "Mail Server %s Connected"%self.smtp
        for mail_addr in self.to_list:
            print "Sending mail to ",mail_addr
            headers = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n"\
                % (self.from_addr, mail_addr, self.subject)
            msg = headers + self.pend_mesg
            try:
                server.sendmail(self.from_addr,mail_addr,msg)
            except smtplib.SMTPException,err:
                print "Send mail failed,Please check your mail account setting in pluster.cfg",err
        server.quit()
        self.pend_mesg = ""




class LogDoc(IDocument):
    """PlusterStatic Log class.       """
    def __init__(self):
        IDocument.__init__(self)
        self.logQueue=Queue.Queue()
        self.file_on = PConfig.attribute.logger_file_on
        self.mail_on = PConfig.attribute.logger_mail_on
        if self.file_on:
            self.file_name = PConfig.attribute.logger_file_name
            self.file_size_limit = PConfig.attribute.logger_file_size_limit
            self.StartFileLog(self.file_name)
        if self.mail_on:
            self.StartMailLog()

    def StartViewLog(self):
        self.viewLog=ViewLoggerHandle(self)
        self.viewLog.setLevel(logging.INFO)
        logging.getLogger().addHandler(self.viewLog)
    def StopViewLog(self):
        logging.getLogger().removeHandler(self.viewLog)

    def StartMailLog (self):
        """ Start Mail Log"""
        addr = PConfig.attribute.cluster_mail
        passwd = PConfig.attribute.cluster_passwd
        smtp = PConfig.attribute.cluster_smtp
        send_to = PConfig.attribute.cluster_send_to
        self.mail=MailLoggerHandler(send_to,smtp,addr,passwd,\
                                        'Critical Message from pluster')
        self.mail.setLevel(logging.CRITICAL)
        logging.getLogger().addHandler(self.mail)
        #print "Start Mail Logger"

    def StopMailLog (self):
        """ Stop Mail Log Handler"""
        logging.getLogger().removeHandler(self.mail)

    def StartFileLog(self,name):
        """Bind a FileHandler to current loger name=filename"""
        self.fileLog=logging.FileHandler(name,'a')
        formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        self.fileLog.setFormatter(formatter)
        self.fileLog.setLevel(logging.ERROR)
        size_filter = FileSizeFilter(self.file_name, \
                                         self.file_size_limit)
        self.fileLog.addFilter(size_filter)
        logging.getLogger().addHandler(self.fileLog)
        #print "Start File Logger"

    def StopFileLog(self):
        logging.getLogger().removeHandler(self.fileLog)

    def RemoveLogFile (self,name):
        """ Remove Log file
        if fail, Raise Exception"""
        os.remove(name)


    def GetNewLog(self,fmt='%(asctime)s %(message)s', datefmt='%H:%M:%S'):
        """ Convert log messages to text. On formats see
        logger.Formatter"""
        f=logging.Formatter(fmt, datefmt)
        buf=StringIO.StringIO()
        buf.write(f.format(self.logQueue.get_nowait()))
        text=buf.getvalue()
        return text+"\n"

class LogView:
    """ Display log messages of a program """
    def __init__(self,parent):
        """ Create and display window. Log is CumulativeLogger. """
        self.parent=parent
        self.t=parent.Form1.LogTextBox.text
        self.t.see(Tkinter.END)
        self.limit=PConfig.attribute.logger_view_limit

    def logTest(self):
        logging.warning("hello")
        ##    self.t.configure(state=Tkinter.NORMAL)
        ##    self.t.insert(Tkinter.END,"sdfsdfsdf\n")
        ##    self.t.configure(state=Tkinter.DISABLED)
    def Update(self,doc):
        try:
            if float(self.t.index(Tkinter.END))>self.limit:
                self.t.delete(1.0,Tkinter.END)
            self.t.insert(Tkinter.END,doc.GetNewLog())
            self.t.see(Tkinter.END)
        except:
            print "logging error while updateing LogView"
            raise

class LogApp(IController):
    def __init__(self):
        IController.__init__(self)
        self.root = Tkinter.Tk()
        self.addView=LogView(self.root)
        self.addDoc=LogDoc()
        #self.addAdp=LogAdapter(self.addView)
        self.addDoc.AddObserver(self.addView)
        self.addDoc.StartViewLog()
        #self.Bind(self.addView,self.addAdp)
    def Start(self):
        self.root.mainloop()
    def Stop(self):
        self.addDoc.StopViewLog()
    def HandleRequest(self, view, aList):
        self.viewToDoc[view].HandleRequest(aList)



